#pragma once

#include "DesignExtractor.h"
#include "DesignEntity.h"
#include "AST.h"
#include "Uses.h"
#include "Modifies.h"
#include <algorithm>
using namespace std;

DesignExtractor::DesignExtractor(AST programAST){
	this->programAST = programAST;
}

void DesignExtractor::getUsedIndexes(Node *root, vector<int> &indexes){
	vector<Node*> children = root->getChildren();

	if(root->getDesignEntity()->getType() == ASSIGN){
		getUsedIndexes(children[1], indexes);
		return;
	}
	
	if(root->getDesignEntity()->getType() == VARIABLE){
		DesignEntity *varDE = root->getDesignEntity();
		Variable *var = dynamic_cast<Variable*>(varDE);
		if(find(indexes.begin(),indexes.end(),var->getIndex()) == indexes.end()){
			indexes.push_back(var->getIndex());
		}
	}

	for(int i=0;i< (int) children.size();i++){
		getUsedIndexes(children[i], indexes);
	}
}

void DesignExtractor::buildUses(Node *root, Uses &usesTable){
	if(root->getDesignEntity()->getType() == ASSIGN 
		|| root->getDesignEntity()->getType() == WHILE){
			vector<int> usedIndexes;
			getUsedIndexes(root, usedIndexes);
			for(int i=0;i< (int) usedIndexes.size();i++){
				usesTable.addUsesStatement(root->getStmtNumber(), usedIndexes[i]);
			}
	}

	vector<Node*> children = root->getChildren();
	for(int i=0;i< (int) children.size();i++){
		buildUses(children[i], usesTable);
	}
}
	
void DesignExtractor::createUsesTable(Uses &usesTable){
	buildUses(programAST.getRoot(), usesTable);
}

void DesignExtractor::getModifiedIndexes(Node *root, vector<int> &indexes){
	if(root->getDesignEntity()->getType() == ASSIGN){
		vector<Node*> children = root->getChildren(); 
		DesignEntity *varDE = children[0]->getDesignEntity();
		Variable *var = dynamic_cast<Variable*>(varDE);
		if(find(indexes.begin(),indexes.end(),var->getIndex()) == indexes.end()){
			indexes.push_back(var->getIndex());
		}
	}

	vector<Node*> children = root->getChildren();
	for(int i=0;i< (int) children.size();i++){
		getModifiedIndexes(children[i], indexes);
	}
}

void DesignExtractor::buildModifies(Node *root, Modifies &modifiesTable){
	if(root->getDesignEntity()->getType() == ASSIGN){
		vector<Node*> children = root->getChildren(); 
		DesignEntity *varDE = children[0]->getDesignEntity();
		Variable *var = dynamic_cast<Variable*>(varDE);
		modifiesTable.addStmtModifies(root->getStmtNumber(),var->getIndex());
	}

	if(root->getDesignEntity()->getType() == WHILE){
		vector<int> modifiedIndexes;
		getModifiedIndexes(root, modifiedIndexes);
		for(int i=0;i< (int) modifiedIndexes.size();i++){
			modifiesTable.addStmtModifies(root->getStmtNumber(), modifiedIndexes[i]);
		}
	}

	vector<Node*> children = root->getChildren();
	for(int i=0;i< (int) children.size();i++){
		buildModifies(children[i], modifiesTable);
	}
}

void DesignExtractor::createModifiesTable(Modifies &modifiesTable){
	buildModifies(programAST.getRoot(), modifiesTable);
}
